package com.myk.game.gobangchess.rooms;

import com.myk.game.gobangchess.Room;
import com.myk.game.gobangchess.Sign;
import com.myk.game.gobangchess.constants.ColorCost;
import com.myk.game.gobangchess.constants.WinMode;
import com.myk.game.gobangchess.signs.*;
import com.myk.game.gobangchess.utils.GridsUtils;

import java.util.*;

/**
 * 史莱姆不连三
 */
public class SlimeNotConnectThreeRoom extends Room {

    private CacheSign cacheSign; //缓存标记

    private final int boardRow,boardCol; //棋盘实际行列
    private final int deckOneIndex, deckTwoIndex, deckThreeIndex, deckStoreIndex; //牌库在界面上的索引， 以及牌库集合的键名
    private final int handOneIndex, handTwoIndex; //抽出到手中的史莱姆预览位置索引,和集合键名

    private Map<Integer,List<Piece>> decksAndPieces; //牌库容器
    private Map<Integer,Piece> handPieces; //抽出在手上的棋子
    private List<Piece> boardPieces; //放置在场上的棋子集合
    private List<Integer> fallLimitRange; //落子限制范围
    private List<Integer> connect3Line; //连三坐标索引集合
    private DoRuleAgent doRuleAgent; //当前交互代理

    public SlimeNotConnectThreeRoom(String roomName) {
        super(roomName, "这是[爱玩游戏的总监]设计的桌游的线上版本。", "史莱姆不连三", GridsUtils.createEmptyGrids(6,6), true, true);
        boardRow = 5;
        boardCol = 5;
        deckOneIndex = getIndex(5,0);
        deckTwoIndex = getIndex(5,1);
        deckThreeIndex = getIndex(5,2);
        deckStoreIndex = getIndex(5,5);
        handOneIndex = getIndex(0,5);
        handTwoIndex = getIndex(1,5);
        initBackground();
    }

    //初始化棋盘缓存背景
    private void initBackground() {
        int row = curGrids.length;
        int col = curGrids[0].length;
        //背景
        List<Sign> chessboardStyle = new ArrayList<>();

        //将画布默认格子隐藏了
        chessboardStyle.add(new GroundSign(getIndex(0, 0), getIndex(row - 1, col - 1), ColorCost.TABLECLOTH_COLOR, ColorCost.TABLECLOTH_COLOR, 2.0f, 0, 0));
        //绘制牌库区域
        chessboardStyle.add(new GroundSign(deckOneIndex, "#33FF66EE", "#99FF66EE", 0.3f, 0, 1));
        chessboardStyle.add(new GroundSign(deckTwoIndex, "#33FF66EE", "#99FF66EE", 0.3f, 0, 1));
        chessboardStyle.add(new GroundSign(deckThreeIndex, "#33FF66EE", "#99FF66EE", 0.3f, 0, 1));
        //绘制石化牌库区域
        chessboardStyle.add(new GroundSign(deckStoreIndex, "#33666666", "#99666666", 0.3f, 0, 1));
        //绘制手牌区域
        chessboardStyle.add(new GroundSign(handOneIndex, "#3366FFEE", "#9966FFEE", 0.3f, 0, 1));
        chessboardStyle.add(new GroundSign(handTwoIndex, "#3366FFEE", "#9966FFEE", 0.3f, 0, 1));

        //绘制棋盘
        for (int i = 0; i < boardRow; i++) {
            for (int j = 0; j < boardCol; j++) {
                chessboardStyle.add(new GroundSign(getIndex(i, j), "#33FFFFFF", "#FF000000", 1.5f));
            }
        }

        //添加到缓存标记
        cacheSign = new CacheSign(this, "background", 5, true, chessboardStyle); //*** 修改背景样式记得改这里的版本号！！！
    }

    @Override
    public String getCoordMode() {
        return "31000101";
    }

    @Override
    public CacheSign getCacheSignByName(String cacheName) {
        return cacheSign;
    }

    @Override
    public String getRuleText() {
        return "《史莱姆不连三-游戏规则》\n" +
                "游戏配置：5x5大小棋盘，3个初始史莱姆牌堆，1个石化史莱姆牌堆。\n" +
                "   21张活跃史莱姆(其中3张万能史莱姆)，1张石化史莱姆，所有史莱姆不分归属双方共有。\n" +
                "游戏目标：让对方行动时形成3只以上同类型史莱姆练成一条线，你即可获胜。\n" +
                "   （石化史莱姆和非石化史莱姆分为不同类型）" +
                "游戏流程：开局21张活跃史莱姆牌随机洗混后等分成3份到3个初始排堆。1张石化史莱姆放到石化牌堆。\n" +
                "随后双方轮流行动，选择以下2个动作之一执行，直到游戏结束。\n" +
                "A.从任意1组堆顶选择1只史莱姆放置在棋盘上。\n" +
                "B.石化棋盘上1只史莱姆并且发动其技能。\n" +
                "放置规则：部分史莱姆标记有限定数字，这样的史莱姆落下后会形成限定区域，\n" +
                "   下一个史莱姆只能放置在该史莱姆限定数字步数范围内。\n" +
                "史莱姆技能：\n" +
                "选：从1组牌堆中选择1只史莱姆放置在棋盘上并洗混该牌堆。\n" +
                "摸：从牌堆顶摸2只史莱姆并且可不限范围地放置在棋盘上。\n" +
                "变：指定棋盘中1只活跃史莱姆变成石头史莱姆(不触发技能)。\n" +
                "扔：把1只史莱姆扔出棋盘并石化(不能选择自己)。\n" +
                "炸：把2只石化史莱姆炸出棋盘，或1只活跃史莱姆炸出棋盘并石化(不能选择自己)。\n" +
                "换：交换2只史莱姆的位置。\n" +
                "移：移动任意1只史莱姆的位置，形成新的限定区域，下个史莱姆落下的位置受其影响；若其为活跃的飞行史莱姆则可以占据活跃的陆行史莱姆的位置，若为万能史莱姆则可以占据任何史莱姆的位置，被占位的史莱姆移出棋盘并石化。\n" +
                "(当发动变、扔、炸、换时，限定区域取消，下只史莱姆可不限范围地放置。)\n" +
                "万能史莱姆：视作所有类型史莱姆\n" +
                "石化牌堆：所有的石化史莱姆移除棋盘会放到石化牌堆。";
    }

    @Override
    protected void onStartPrepare() {
        //创建全部的21张史莱姆并乱序
        List<Piece> allPieces = createAndShuffleAllPieces();
        //创建牌堆容器
        decksAndPieces = new HashMap<>();
        //使用新的ArrayList而不是subList，避免并发修改异常
        decksAndPieces.put(deckOneIndex, new ArrayList<>(allPieces.subList(0, allPieces.size()/3)));//平均分三分到三个初始牌堆
        decksAndPieces.put(deckTwoIndex, new ArrayList<>(allPieces.subList(allPieces.size()/3, allPieces.size()/3*2)));//平均分三分到三个初始牌堆
        decksAndPieces.put(deckThreeIndex, new ArrayList<>(allPieces.subList(allPieces.size()/3*2, allPieces.size())));//平均分三分到三个初始牌堆
        List<Piece> deckStorePieces = new ArrayList<>();
        Piece stonePiece = new Piece(this,-1);
        stonePiece.setStone();
        deckStorePieces.add(stonePiece);
        decksAndPieces.put(deckStoreIndex, new ArrayList<>(deckStorePieces)); //创建初始石化牌堆
        //创建手牌容器
        handPieces = new HashMap<>();
        handPieces.put(handOneIndex, null);
        handPieces.put(handTwoIndex, null);
        //创建棋盘容器
        boardPieces = new ArrayList<>();
        //默认通知黑方先行动
        noticeBlackMove();
    }

    @Override
    public void resetGrids() {
        super.resetGrids();
        boardPieces = null;
        decksAndPieces = null;
        handPieces = null;
        fallLimitRange = null;
        connect3Line = null;
        doRuleAgent = null;
    }

    @Override
    public String getGameInfo() {
        if (doRuleAgent != null){
            doRuleAgent.onRender();
        }
        else {
            normalRender();
        }
        return super.getGameInfo();
    }

    @Override
    public void doRule(int row, int col, int value) {
        if (doRuleAgent != null){
            doRuleAgent.onClick(row, col);
        }
        else {
            normalClick(row, col);
        }
    }

    //默认点击事件处理
    private void normalClick(int row, int col) {
        //手牌中没有史莱姆时
        if (handPieces.get(handOneIndex) == null){
            int index = getIndex(row, col);
            //点击牌库时
            if (isClickDeck(index)){
                List<Piece> pieces = decksAndPieces.get(index);
                //牌堆非空时
                if (pieces != null && pieces.size() > 0){
                    pullPiece(index); //从指定牌库抽卡
                }
            }
            //点击棋盘时
            else if (row < boardRow && col < boardCol){
                Piece piece = getPieceOnBoard(row, col);
                //点击棋盘上有技能的棋子时
                if (piece != null && piece.skill!=null){
                    Skill skill = piece.skill;
                    piece.setStone(); //先石化棋子
                    //判断有没有三连
                    if (!checkConnectThree()){
                        skill.doAction(this, piece); //没有三连就执行技能
                    }
                    else {
                        noticeGameOver("形成三连"); //有三连就通知结束
                    }
                }
            }
        }
        //手牌中有史莱姆时
        else {
            //点击到了棋盘内
            if (row < boardRow && col < boardCol){
                //没有落子限制，或者落在了限制范围内时
                if (fallLimitRange == null || fallLimitRange.contains(getIndex(row, col))){
                    Piece boardPiece = getPieceOnBoard(row, col);
                    //放置到空格时
                    if (boardPiece == null){
                        fallPiece(row, col); //放置史莱姆
                        checkGameOver(); //判断游戏是否结束
                    }
                }
            }
        }
    }

    //默认的界面绘制
    public void normalRender() {
        //先全部初始化
        curGrids = GridsUtils.copyGrids(originGrids);
        signList.clear();

        //绘制界面背景
        signList.add(cacheSign);

        //绘制牌堆上的棋子
        if (decksAndPieces != null){
            decksAndPieces.forEach((index, pieces) -> {
                if (pieces!=null && pieces.size() > 0){
                    Piece piece = pieces.get(0); //获取牌堆顶的牌
                    piece.render(index); //绘制牌堆顶的牌
                    //绘制牌堆剩余史莱姆数量
                    signList.add(new BadgeSign(index,pieces.size() + "",6,"#99666666",ColorCost.TRANSPARENT));
                }
            });
        }

        //绘制手牌上的棋子
        if (handPieces != null){
            handPieces.forEach((index, piece) -> {
                if (piece != null) {
                    piece.render(index);
                }
            });
        }

        //绘制场上棋子
        if (boardPieces != null){
            for (Piece piece : boardPieces) {
                piece.render(getIndex(piece.boardRow, piece.boardCol));
            }
        }

        //绘制落子限制提示
        if (fallLimitRange != null){
            List<Integer> indexes = new ArrayList<>();
            for (int i = 0; i < boardRow; i++) {
                for (int j = 0; j < boardCol; j++) {
                    if (curGrids[i][j] == 0){
                        indexes.add(getIndex(i, j));
                    }
                }
            }
            indexes.removeAll(fallLimitRange);
            signList.add(new ColorSign(indexes, "#55111111"));
        }

        //绘制连三提示
        if (connect3Line != null){
            signList.add(new AroundSign(connect3Line, "#55EE1111", ColorCost.TRANSPARENT, 1.0f));
        }

        //绘制操作提示
        if (cur == 1 || cur == 2){
            if (handPieces.get(handOneIndex) != null){
                if (fallLimitRange != null){
                    gameTip = "请将史莱姆放置到棋盘上限定空格中";
                }
                else {
                    gameTip = "请将史莱姆放置到棋盘上任意空格中";
                }
            }
            else {
                gameTip = "请从牌库中抽取一张史莱姆，或使用场上史莱姆的技能";
            }
        }
        else if (connect3Line != null){
            gameTip = "史莱姆连三了！游戏结束。。";
        }
        else {
            gameTip = "-1";
        }
    }

    //创建所有棋子21张史莱姆并且乱序返回
    private List<Piece> createAndShuffleAllPieces() {
        List<Piece> pieces = new ArrayList<>();
        pieces.add(new Piece(this,-1).withUniversal()); //万能史莱姆
        pieces.add(new Piece(this,-1).withUniversal()); //万能史莱姆
        pieces.add(new Piece(this,-1).withUniversal()); //万能史莱姆
        pieces.add(new Piece(this,3)); //无技能陆行史莱姆
        pieces.add(new Piece(this,3)); //无技能陆行史莱姆
        pieces.add(new Piece(this,3).withFlying()); //无技能飞行史莱姆
        pieces.add(new Piece(this,3).withFlying()); //无技能飞行史莱姆
        pieces.add(new Piece(this,1).withSkill(Skill.createXuan())); //选技能陆行史莱姆
        pieces.add(new Piece(this,1).withFlying().withSkill(Skill.createXuan())); //选技能飞行史莱姆
        pieces.add(new Piece(this,2).withSkill(Skill.createMo())); //摸技能陆行史莱姆
        pieces.add(new Piece(this,2).withFlying().withSkill(Skill.createMo()));//摸技能飞行史莱姆
        pieces.add(new Piece(this,1).withSkill(Skill.createBian())); //变技能陆行史莱姆
        pieces.add(new Piece(this,1).withFlying().withSkill(Skill.createBian())); //变技能飞行史莱姆
        pieces.add(new Piece(this,1).withSkill(Skill.createReng())); //扔技能陆行史莱姆
        pieces.add(new Piece(this,1).withFlying().withSkill(Skill.createReng())); //扔技能飞行史莱姆
        pieces.add(new Piece(this,2).withSkill(Skill.createZha())); //炸技能陆行史莱姆
        pieces.add(new Piece(this,2).withFlying().withSkill(Skill.createZha())); //炸技能飞行史莱姆
        pieces.add(new Piece(this,2).withSkill(Skill.createHuan())); //换技能陆行史莱姆
        pieces.add(new Piece(this,2).withFlying().withSkill(Skill.createHuan())); //换技能飞行史莱姆
        pieces.add(new Piece(this,1).withSkill(Skill.createYi())); //移技能陆行史莱姆
        pieces.add(new Piece(this,1).withFlying().withSkill(Skill.createYi())); //移技能飞行史莱姆
        //打乱顺序
        Collections.shuffle(pieces);
        return pieces;
    }

    //判断是否点击了非空的牌库
    private boolean isClickDeck(int index) {
        return index == deckOneIndex || index == deckTwoIndex || index == deckThreeIndex || index == deckStoreIndex;
    }

    //抽取史莱姆
    private void pullPiece(int index) {
        Piece piece = decksAndPieces.get(index).remove(0); //取牌堆顶的牌
        handPieces.put(handOneIndex, piece); //拿到手牌

        //判断是否可以落子
        if (checkCanMove()) {
            noticeAllRefreshGameInfo();
        }
        else {
            noticeGameOver("无路可走");
        }
    }

    //放置史莱姆
    private void fallPiece(int row, int col) {
        Piece selectPiece = handPieces.remove(handOneIndex); //从手牌中拿走牌
        boardPieces.add(selectPiece); //放置到棋盘上
        selectPiece.setBoardPos(row, col); //设置棋子位置
        updateLimitRange(selectPiece); //更新限定区域提示
    }

    //移除史莱姆
    private void removePiece(Piece moveToPiece) {
        boardPieces.remove(moveToPiece); //从棋盘上移除棋子
        moveToPiece.setStone(); //移除的棋子都会强制石化
        decksAndPieces.get(deckStoreIndex).add(0, moveToPiece); //移除的棋子都会放入石化牌库里
    }

    //更新落子限制
    private void updateLimitRange(Piece piece) {
        if (piece.limitRange > 0){
            fallLimitRange = new ArrayList<>();
            for (int i = 0; i < boardRow; i++) {
                for (int j = 0; j < boardCol; j++) {
                    if (curGrids[i][j] == 0){
                        int distance = Math.abs(i - piece.boardRow) + Math.abs(j - piece.boardCol); //始终使用曼哈顿距离，不考虑任何阻拦
                        if (distance <= piece.limitRange && distance!=0) {
                            fallLimitRange.add(getIndex(i, j));
                        }
                    }
                }
            }
        }
        else {
            fallLimitRange = null;
        }
    }

    //获取棋盘上的棋子
    private Piece getPieceOnBoard(int row, int col) {
        for (Piece piece : boardPieces) {
            if (piece.boardRow == row && piece.boardCol == col){
                return piece;
            }
        }
        return null;
    }

    //判断游戏是否结束
    private void checkGameOver() {
        if (!checkConnectThree()){
            noticeChangeMove();  //没有三连就切换行动方
        }
        else {
            noticeGameOver("形成三连"); //有三连就通知结束
        }
    }

    //检查是否三连
    private boolean checkConnectThree() {
        //检查所有方向：横、竖、两个对角线
        int[][] directions = {{0, 1}, {1, 0}, {1, 1}, {1, -1}};
        
        //遍历棋盘上的每个位置作为起点
        for (int startRow = 0; startRow < boardRow; startRow++) {
            for (int startCol = 0; startCol < boardCol; startCol++) {
                Piece startPiece = getPieceOnBoard(startRow, startCol);
                if (startPiece == null) continue;
                
                //对每个方向进行检查
                for (int[] dir : directions) {
                    List<Integer> currentLine = new ArrayList<>();
                    List<Boolean> typeList = new ArrayList<>();
                    
                    //向正方向检查
                    checkDirection(startRow, startCol, dir[0], dir[1], startPiece, currentLine,typeList, true);
                    //向负方向检查
                    checkDirection(startRow, startCol, -dir[0], -dir[1], startPiece, currentLine,typeList, false);

                    //如果当前线路有3个或以上相同类型棋子
                    if (currentLine.size() >= 3 && checkAllSameType(typeList)) {
                        if (connect3Line == null){
                            connect3Line = new ArrayList<>();
                        }
                        connect3Line.addAll(currentLine);
                    }
                }
            }
        }
        return connect3Line != null;
    }

    //辅助方法：检查所有类型是否都相同，因为如果万能史莱姆当起点检查时可能让头围不同类型的拼成一行
    private boolean checkAllSameType(List<Boolean> typeList) {
        if (typeList.size() > 0){
            for (int i = 1; i < typeList.size(); i++) {
                if (typeList.get(i) != typeList.get(0)){
                    return false;
                }
            }
        }
        return true;
    }

    //辅助方法：检查指定方向的相同类型棋子
    private void checkDirection(int startRow, int startCol, int dRow, int dCol, Piece startPiece, List<Integer> currentLine, List<Boolean> typeList, boolean isStartPoint) {
        int row = startRow + dRow;
        int col = startCol + dCol;
        Piece typeBase = startPiece;

        while (row >= 0 && row < boardRow && col >= 0 && col < boardCol) {
            Piece currentPiece = getPieceOnBoard(row, col);
            if (currentPiece == null) break;
            
            //检查是否同类型（考虑万能史莱姆）
            if (isSameType(typeBase, currentPiece)) {
                int index = getIndex(row, col);
                if (!currentLine.contains(index)) {
                    currentLine.add(index);
                    if (!currentPiece.isUniversal){ //避免被万能史莱姆污染类型基准
                        typeList.add(currentPiece.isStone);
                        typeBase = currentPiece;
                    }
                }
                row += dRow;
                col += dCol;
            } else {
                break;
            }
        }
        
        //如果是起点，添加起点到列表
        if (isStartPoint) {
            int startIndex = getIndex(startRow, startCol);
            if (!currentLine.contains(startIndex)) {
                currentLine.add(startIndex);
            }
        }
    }
    
    //辅助方法：判断两个棋子是否为同类型
    private boolean isSameType(Piece piece1, Piece piece2) {
        //如果其中任意一个是万能史莱姆，则视为同类型
        if (piece1.isUniversal || piece2.isUniversal) {
            return true;
        }
        
        //石化状态必须相同（石化史莱姆和非石化史莱姆视为不同类型）
        return piece1.isStone == piece2.isStone;
    }

    //检查是否无路可走
    private boolean checkCanMove() {
        //一旦发现有落子限制，就要查找是否有可落子的空格，size==0说明没有空格
        if (fallLimitRange != null && fallLimitRange.size() == 0){
            //检查手上是否有棋子
            if (handPieces.get(handOneIndex) != null){
                return false;//手上有棋子就没法落下了
            }
            //手上没有棋子时，检查场上的棋子是否有技能可以触发
            for (Piece boardPiece : boardPieces) {
                if (boardPiece.skill != null){
                    return true; //找到技能
                }
            }
            //也不能落子，也没有技能，直接凉凉
            return false;
        }
        return true; //没有落子限制就默认可以落子，因为所有史莱姆都在场上都不会填满棋盘
    }

    //切换行动方
    private void noticeChangeMove() {
        stepAdd(); //增加步数

        //切换行动方
        if (cur == 1){
            noticeWhiteMove();
        }
        else {
            noticeBlackMove();
        }

        //检查是否无路可走
        if (!checkCanMove()) {
            noticeGameOver("无路可走"); //通知结束
        }
    }

    //通知游戏结束
    private void noticeGameOver(String reason) {
        if (cur==1){
            doOver(WinMode.WHITE_WIN,"黑方" + reason + " 白方获胜！");
        }
        else {
            doOver(WinMode.BLACK_WIN,"白方" + reason + "黑方获胜！" );
        }
    }

    /**
     * 棋子
     */
    private static class Piece {
        private SlimeNotConnectThreeRoom room;
        private int boardRow; //在棋盘上的行
        private int boardCol; //在棋盘上的列
        private boolean isStone; //是否石化史莱姆
        private boolean isFlying; //是否是飞行史莱姆
        private boolean isUniversal; //是否万能史莱姆
        private int limitRange; //限定范围
        private Skill skill; //技能

        public Piece(SlimeNotConnectThreeRoom room, int limitRange) {
            this.room = room;
            this.limitRange = limitRange;
        }

        public Piece withFlying() {
            this.isFlying = true;
            return this;
        }

        public Piece withSkill(Skill skill) {
            this.skill = skill;
            return this;
        }

        public Piece withUniversal() {
            this.isUniversal = true;
            this.limitRange = -1;
            return this;
        }

        public void setBoardPos(int row, int col) {
            this.boardRow = row;
            this.boardCol = col;
        }

        public void setStone() {
            this.isStone = true;
            this.isUniversal = false;
            this.limitRange = -1;
            this.skill = null;
        }

        public void render(int index) {
            //获取索引
            int row = room.getRowByIndex(index);
            int col = room.getColByIndex(index);

            //石化史莱姆
            if (isStone){
                room.curGrids[row][col] = 7;
                room.signList.add(new TitleSign((col + 0.5f) / room.curGrids[0].length, (row + 0.5f) / room.curGrids.length, 0, "-_-", ColorCost.GRAY, 0.33f));
            }
            //万能史莱姆
            else if (isUniversal){
                room.curGrids[row][col] = 2;
                room.signList.add(new TitleSign((col + 0.5f) / room.curGrids[0].length, (row + 0.5f) / room.curGrids.length, 0, "ଘ0ω0ଓ", "#FFFFFF66", 0.33f));
                room.signList.add(new TitleSign((col + 0.5f) / room.curGrids[0].length, (row + 0.5f) / room.curGrids.length, 0, "0ω0", "#FF66FFFF", 0.33f));
                room.signList.add(new TitleSign((col + 0.5f) / room.curGrids[0].length, (row + 0.5f) / room.curGrids.length, 0, "ω", "#FFFF66FF", 0.33f));
            }
            //普通史莱姆
            else {
                room.curGrids[row][col] = 2;
                //飞行史莱姆
                if (isFlying){
                    room.signList.add(new TitleSign((col + 0.5f) / room.curGrids[0].length, (row + 0.5f) / room.curGrids.length, 0, "ଘ0_0ଓ", ColorCost.BLACK, 0.33f));
                }
                //陆行史莱姆
                else {
                    room.signList.add(new TitleSign((col + 0.5f) / room.curGrids[0].length, (row + 0.5f) / room.curGrids.length, 0, "0_0", ColorCost.BLACK, 0.33f));
                }
                if (limitRange > 0){
                    room.signList.add(new BadgeSign(index, limitRange + "", 8, ColorCost.BLACK, ColorCost.TRANSPARENT)); //显示限定范围
                }
                if (skill != null){
                    room.signList.add(new BadgeSign(index, skill.name, 0, ColorCost.BLUE, ColorCost.TRANSPARENT)); //显示技能名称
                }
            }

        }

        public void renderInSkill(String skillName) {
            room.signList.add(new BadgeSign(room.getIndex(boardRow, boardCol), skillName, 2, ColorCost.RED_TEXT, ColorCost.TRANSPARENT)); //显示生效中的技能名称
        }
    }

    /**
     * 技能
     */
    private abstract static class Skill {
        private final String name; //技能名称
        public Skill(String name) {
            this.name = name;
        }

        public String getSkillName() {
            return name;
        }

        /**
         * 执行技能效果
         */
        public abstract void doAction(SlimeNotConnectThreeRoom room,Piece sourcePiece);

        /**
         * 技能：选
         */
        public static Skill createXuan(){
            return new Skill("选") {

                boolean isShowPlatform = false; //是否打开牌库展示台
                int recordSelectedDeckIndex = -1; //记录你查看的牌库
                List<Integer> platformIndexes = new ArrayList<>(); //展示台坐标索引

                @Override
                public void doAction(SlimeNotConnectThreeRoom room,Piece sourcePiece) {
                    //构建展示台坐标
                    initPlatformIndexes(room);
                    //设置交互代理
                    room.doRuleAgent = new DoRuleAgent() {
                        @Override
                        public void onClick(int row, int col) {
                            int index = room.getIndex(row, col);
                            //手中没有牌的时候
                            if (room.handPieces.get(room.handOneIndex) == null){
                                //显示了展示台时
                                if (isShowPlatform){
                                    //点击了展示台内的区域
                                    if (platformIndexes.contains(index)){
                                        List<Piece> deckPieces = room.decksAndPieces.get(recordSelectedDeckIndex); //获取牌堆
                                        int no = platformIndexes.indexOf(index); //获取顺数序号
                                        if (no>=0 && no < deckPieces.size()){
                                            Piece piece = deckPieces.remove(no); //牌堆里取走你选的牌
                                            room.handPieces.put(room.handOneIndex, piece); //添加到手牌
                                            Collections.shuffle(deckPieces); //重新乱序该牌堆剩余的牌
                                            isShowPlatform = false; //关闭展示台

                                            //检查是否无路可走
                                            if (!room.checkCanMove()) {
                                                room.noticeGameOver("无路可走"); //通知结束
                                            }
                                            else {
                                                room.noticeAllRefreshGameInfo(); //重新刷新界面
                                            }
                                        }
                                    }
                                    //点击了展示台之外的区域，关闭展示台，为了方便再观察观察局面
                                    else {
                                        isShowPlatform = false; //关闭展示台
                                        room.noticeAllRefreshGameInfo();
                                    }
                                }
                                //关闭了展示台时
                                else {
                                    //之前点开过牌堆,
                                    if (room.isClickDeck(recordSelectedDeckIndex)) {
                                        //点击的是之前打开的牌堆
                                        if (recordSelectedDeckIndex == index){
                                            isShowPlatform = true; //打开牌库展示台
                                            room.noticeAllRefreshGameInfo();
                                        }
                                    }
                                    //之前没有点开过牌堆
                                    else {
                                        //点击了牌堆,记录初次点开牌堆,锁定本次技能只能看这个牌堆了
                                        if (room.isClickDeck(index) && room.decksAndPieces.get(index).size()>0){
                                            recordSelectedDeckIndex = index; //记录你打开的牌堆
                                            isShowPlatform = true; //打开牌库展示台
                                            room.noticeAllRefreshGameInfo();
                                        }
                                    }
                                }
                            }
                            //手中有牌的时候
                            else {
                                //点击了棋盘时
                                if (row < room.boardRow && col < room.boardCol){
                                    //没有落子限制，或者落在了限制范围内时
                                    if (room.fallLimitRange == null || room.fallLimitRange.contains(index)){
                                        Piece boardPiece = room.getPieceOnBoard(row, col);
                                        //放置到空格时
                                        if (boardPiece == null){
                                            room.fallPiece(row,col); //落子
                                            room.doRuleAgent = null; //移除交互代理
                                            room.checkGameOver(); //判断游戏是否结束
                                        }
                                    }
                                }
                            }

                        }

                        @Override
                        public void onRender() {
                            //显示某个牌库中所有棋子的展示台
                            if (isShowPlatform){
                                int row = room.curGrids.length;
                                int col = room.curGrids[0].length;
                                //先全部初始化
                                room.curGrids = GridsUtils.copyGrids(room.originGrids);
                                room.signList.clear();
                                //将画布默认格子隐藏了
                                room.signList.add(new GroundSign(room.getIndex(0, 0), room.getIndex(row - 1, col - 1), ColorCost.TABLECLOTH_COLOR, ColorCost.TABLECLOTH_COLOR, 2.0f, 0, 0));
                                //绘制8个虚线框
                                for (Integer index : platformIndexes) {
                                    room.signList.add(new GroundSign(index, "#33FF66EE", "#99FF66EE", 0.3f, 0, 1));
                                }
                                //绘制牌库中的棋子
                                List<Piece> pieces = room.decksAndPieces.get(recordSelectedDeckIndex);
                                for (int i = 0; i < 8 && i < pieces.size(); i++) {
                                    Piece piece = pieces.get(i);
                                    if (piece != null){
                                        piece.render(platformIndexes.get(i));
                                    }
                                }

                                room.gameTip = "从该牌堆中选择1只史莱姆";
                            }
                            //看棋盘界面
                            else {
                                //绘制棋盘
                                room.normalRender();
                                //提示正在使用技能的棋子
                                sourcePiece.renderInSkill(getSkillName());
                                //绘制锁定选中的棋盘
                                if (recordSelectedDeckIndex > 0){
                                    room.signList.add(new GroundSign(recordSelectedDeckIndex,ColorCost.TRANSPARENT,"#FF66FFEE",0.5f,0,0));
                                }
                                room.gameTip = "请选择要查看的牌堆";
                            }
                        }
                    };
                    //刷新界面
                    room.noticeAllRefreshGameInfo();
                }

                //构建牌库展示台 2行4列居中
                private void initPlatformIndexes(SlimeNotConnectThreeRoom room){
                    List<Integer> indexes = new ArrayList<>();
                    for (int i = 0; i < 8; i++) {
                        int r = i / 4 + 2;
                        int c = i % 4 + 1;
                        indexes.add(room.getIndex(r, c));
                    }
                    platformIndexes = indexes;
                }
            };
        }

        /**
         * 技能：摸
         */
        public static Skill createMo(){
            return new Skill("摸") {

                @Override
                public void doAction(SlimeNotConnectThreeRoom room,Piece sourcePiece) {
                    //清除落子限制
                    room.fallLimitRange = null;
                    //设置交互代理
                    room.doRuleAgent = new DoRuleAgent() {

                        @Override
                        public void onClick(int row, int col) {
                            Piece selectOne = room.handPieces.get(room.handOneIndex);
                            Piece selectTwo = room.handPieces.get(room.handTwoIndex);
                            int index = room.getIndex(row, col);
                            //手上没有史莱姆
                            if (selectOne == null && selectTwo == null){
                                if (room.isClickDeck(index)){
                                    List<Piece> pieces = room.decksAndPieces.get(index);
                                    if (pieces.size() > 0){
                                        //抽取第一只史莱姆放到手牌第一张中
                                        Piece piece = pieces.remove(0);
                                        room.handPieces.put(room.handOneIndex, piece);
                                        room.noticeAllRefreshGameInfo();
                                    }
                                }
                            }
                            //手上刚抽了一个史莱姆，还要再抽一个
                            if (selectOne!=null && selectTwo == null) {
                                if (room.isClickDeck( index)){
                                    List<Piece> pieces = room.decksAndPieces.get(index);
                                    if (pieces.size() > 0){
                                        //抽取第二只史莱姆放到手牌第二张中
                                        Piece piece = pieces.remove(0);
                                        room.handPieces.put(room.handTwoIndex, piece);
                                        //两个史莱姆都抽取后准备无限制的落子，所以临时清除落子限制
                                        room.fallLimitRange = null;
                                        room.noticeAllRefreshGameInfo();
                                    }
                                }
                            }
                            //第一个史莱姆已经落下，还要再落下另一个
                            if (selectOne == null && selectTwo != null) {
                                //棋盘上空位才能放史莱姆
                                if (row < room.boardRow && col < room.boardCol && room.curGrids[row][col] == 0){
                                    //将第2张史莱姆放到棋盘上
                                    Piece selectPiece = room.handPieces.remove(room.handTwoIndex); //从第2张手牌中拿走棋子
                                    room.boardPieces.add(selectPiece); //放置到棋盘上
                                    selectPiece.setBoardPos(row, col); //设置棋子位置
                                    room.doRuleAgent = null; //移除交互代理
                                    room.checkGameOver(); //当两个都落下后，判断游戏是否结束
                                }
                            }
                            //手上有两个史莱姆了
                            if (selectOne != null && selectTwo != null){
                                //棋盘上空位才能放史莱姆
                                if (row < room.boardRow && col < room.boardCol && room.curGrids[row][col] == 0){
                                    //将第一张史莱姆放到棋盘上
                                    Piece selectOnePiece = room.handPieces.remove(room.handOneIndex); //从第一张手牌中拿走牌
                                    room.boardPieces.add(selectOnePiece); //放置到棋盘上
                                    selectOnePiece.setBoardPos(row, col); //设置棋子位置
                                    room.noticeAllRefreshGameInfo(); //刷新界面
                                }
                            }
                        }

                        @Override
                        public void onRender() {
                            Piece selectOne = room.handPieces.get(room.handOneIndex);
                            Piece selectTwo = room.handPieces.get(room.handTwoIndex);
                            //手上没有史莱姆
                            if (selectOne == null && selectTwo == null){
                                room.normalRender();
                                room.gameTip = "请从牌堆抽取2只史莱姆";
                            }
                            //手上刚抽了一个史莱姆，还要再抽一个
                            if (selectOne!=null && selectTwo == null) {
                                room.normalRender();
                                room.gameTip = "请从牌堆抽取2只史莱姆";
                            }
                            //第一个史莱姆已经落下，还要再落下另一个
                            if (selectOne == null && selectTwo != null) {
                                room.normalRender();
                                room.gameTip = "请将2只史莱姆放置到棋盘上任意空格中";
                            }
                            //手上有两个史莱姆了
                            if (selectOne != null && selectTwo != null){
                                room.normalRender();
                                room.gameTip = "请将2只史莱姆放置到棋盘上任意空格中";
                            }

                            //提示正在使用技能的棋子
                            sourcePiece.renderInSkill(getSkillName());
                        }


                    };
                    //刷新界面
                    room.noticeAllRefreshGameInfo();
                }

            };
        }

        /**
         * 技能：变
         */
        public static Skill createBian(){
            return new Skill("变") {
                @Override
                public void doAction(SlimeNotConnectThreeRoom room,Piece sourcePiece) {
                    //清除落子限制
                    room.fallLimitRange = null;
                    //场上是否存在活跃的棋子
                    if (isHasActivePiece(room)){
                        //设置交互代理
                        room.doRuleAgent = new DoRuleAgent() {
                            @Override
                            public void onClick(int row, int col) {
                                Piece selectPiece = room.getPieceOnBoard(row, col);
                                if (selectPiece != null && !selectPiece.isStone){
                                    selectPiece.setStone(); //石化选择的活跃史莱姆
                                    room.doRuleAgent = null; //移除交互代理
                                    room.checkGameOver();//判断游戏是否结束
                                }
                            }

                            @Override
                            public void onRender() {
                                room.normalRender();
                                sourcePiece.renderInSkill(getSkillName()); //提示正在使用技能的棋子
                                room.gameTip = "请选择场上1只活跃史莱姆石化";
                            }
                        };
                        //刷新界面
                        room.noticeAllRefreshGameInfo();
                    }
                    //场上不存在活跃的棋子时
                    else {
                        room.noticeChangeMove(); //切换行动方
                    }
                }

                //判断场上是否存在活跃的棋子
                private boolean isHasActivePiece(SlimeNotConnectThreeRoom room) {
                    boolean hasActivePiece = false;
                    for (Piece boardPiece : room.boardPieces) {
                        if (!boardPiece.isStone){
                            hasActivePiece = true;
                            break;
                        }
                    }
                    return hasActivePiece;
                }
            };
        }

        /**
         * 技能：扔
         */
        public static Skill createReng(){
            return new Skill("扔") {
                @Override
                public void doAction(SlimeNotConnectThreeRoom room,Piece sourcePiece) {
                    //清除落子限制
                    room.fallLimitRange = null;
                    //有其它棋子时才要等待选择
                    if (room.boardPieces.size()>1){
                        //设置交互代理
                        room.doRuleAgent = new DoRuleAgent() {

                            @Override
                            public void onClick(int row, int col) {
                                Piece selectPiece = room.getPieceOnBoard(row, col);
                                //选择了其它棋子时
                                if (selectPiece != null && selectPiece != sourcePiece){
                                    room.removePiece(selectPiece); //从棋盘上移除棋子
                                    room.doRuleAgent = null; //移除交互代理
                                    room.noticeChangeMove(); //切换行动方
                                }
                            }

                            @Override
                            public void onRender() {
                                room.normalRender();
                                sourcePiece.renderInSkill(getSkillName()); //提示正在使用技能的棋子
                                room.gameTip = "请选择场上1只其它史莱姆扔掉并石化";
                            }
                        };
                        //刷新界面
                        room.noticeAllRefreshGameInfo();
                    }
                    //当没有其它棋子时直接切换行动方
                    else {
                        room.noticeChangeMove();
                    }
                }
            };
        }

        /**
         * 技能：炸
         */
        public static Skill createZha(){
            return new Skill("炸") {

                private Piece lastZhaPiece; //最近一个炸掉的史莱姆

                @Override
                public void doAction(SlimeNotConnectThreeRoom room,Piece sourcePiece) {
                    //清除落子限制
                    room.fallLimitRange = null;
                    //有其它棋子时才要等待选择
                    if (room.boardPieces.size()>1){
                        //设置交互代理
                        room.doRuleAgent = new DoRuleAgent() {

                            @Override
                            public void onClick(int row, int col) {
                                Piece selectPiece = room.getPieceOnBoard(row, col);
                                //选择了其它棋子时
                                if (selectPiece != null && selectPiece != sourcePiece){
                                    //选择第一个棋子炸掉
                                    if (lastZhaPiece == null){
                                        //第一个选择了活跃棋子炸掉，就直接结束
                                        if (!selectPiece.isStone){
                                            room.removePiece(selectPiece); //从棋盘上移除棋子
                                            room.doRuleAgent = null; //移除交互代理
                                            room.noticeChangeMove(); //切换行动方
                                        }
                                        //第一个选择了石化棋子炸掉
                                        else {
                                            room.removePiece(selectPiece); //从棋盘上移除棋子
                                            //还有剩余的其它石化棋子可供选择时
                                            if (checkHasStorePiece(room, sourcePiece)){
                                                lastZhaPiece = selectPiece; //记录最近一个炸掉的石化史莱姆，再继续选择
                                                room.noticeAllRefreshGameInfo();
                                            }
                                            //当没有其它棋子时直接切换行动方
                                            else {
                                                room.doRuleAgent = null; //移除交互代理
                                                room.noticeChangeMove(); //切换行动方
                                            }
                                        }
                                    }
                                    //选择第二个棋子炸掉
                                    else {
                                        //第二个棋子也得时石化棋子
                                        if (selectPiece.isStone){
                                            room.removePiece(selectPiece); //从棋盘上移除棋子
                                            room.doRuleAgent = null; //移除交互代理
                                            room.noticeChangeMove(); //切换行动方
                                        }
                                    }
                                }
                            }

                            @Override
                            public void onRender() {
                                room.normalRender();
                                sourcePiece.renderInSkill(getSkillName()); //提示正在使用技能的棋子
                                if (lastZhaPiece == null){
                                    room.gameTip = "请选择场上2只石化史莱姆扔掉，或1只活跃史莱姆扔掉并石化";
                                }
                                else {
                                    room.gameTip = "请选择第2只石化史莱姆扔掉";
                                }
                            }
                        };
                        //刷新界面
                        room.noticeAllRefreshGameInfo();
                    }
                    //当没有其它棋子时直接切换行动方
                    else {
                        room.noticeChangeMove();
                    }
                }

                //检查是否还有剩余的其它石化棋子
                private boolean checkHasStorePiece(SlimeNotConnectThreeRoom room,Piece self) {
                    for (Piece piece : room.boardPieces){
                        if (piece.isStone && piece != self){
                            return true;
                        }
                    }
                    return false;
                }
            };
        }

        /**
         * 技能：换
         */
        public static Skill createHuan(){
            return new Skill("换") {

                private Piece lastZhaPiece; //最近一个扎住的史莱姆

                @Override
                public void doAction(SlimeNotConnectThreeRoom room,Piece sourcePiece) {
                    //清除落子限制
                    room.fallLimitRange = null;
                    //有其它棋子时才要等待选择
                    if (room.boardPieces.size()>1){
                        //设置交互代理
                        room.doRuleAgent = new DoRuleAgent() {

                            @Override
                            public void onClick(int row, int col) {
                                Piece selectPiece = room.getPieceOnBoard(row, col);
                                //选择了场上活跃的棋子
                                if (selectPiece != null){
                                    //选择第一个棋子扎住
                                    if (lastZhaPiece == null){
                                        lastZhaPiece = selectPiece;
                                        room.noticeAllRefreshGameInfo();
                                    }
                                    //选择第二个棋子和之前扎住的棋子交换位置
                                    else {
                                        selectPiece.setBoardPos(lastZhaPiece.boardRow,lastZhaPiece.boardCol);
                                        lastZhaPiece.setBoardPos(row,col);
                                        room.doRuleAgent = null; //移除交互代理
                                        room.checkGameOver(); //检查游戏是否结束
                                    }
                                }
                            }

                            @Override
                            public void onRender() {
                                room.normalRender();
                                sourcePiece.renderInSkill(getSkillName()); //提示正在使用技能的棋子
                                if (lastZhaPiece != null){
                                    String s = "⇋"; // ⇋☍⟲⤧
                                    room.signList.add(new TitleSign((lastZhaPiece.boardCol + 0.5f) / room.curGrids[0].length, (lastZhaPiece.boardRow + 0.35f) / room.curGrids.length, 0, s, ColorCost.NEW_PUT_POINT_LIGHT, 0.5f));
                                }
                                room.gameTip = "请选择场上2只史莱姆交换位置";
                            }
                        };
                        //刷新界面
                        room.noticeAllRefreshGameInfo();
                    }
                    //当没有其它棋子时直接切换行动方
                    else {
                        room.noticeChangeMove();
                    }
                }
            };
        }

        /**
         * 技能：移
         */
        public static Skill createYi(){
            return new Skill("移") {

                private Piece selectMovePiece; //选中的想要移动的棋子

                @Override
                public void doAction(SlimeNotConnectThreeRoom room,Piece sourcePiece) {
                    room.fallLimitRange = null;
                    room.doRuleAgent = new DoRuleAgent() {
                        @Override
                        public void onClick(int row, int col) {
                            if (selectMovePiece == null){
                                 selectMovePiece = room.getPieceOnBoard(row, col); //选择棋子选中
                                 room.noticeAllRefreshGameInfo();
                            }
                            else {
                                if (row < room.boardRow && col < room.boardCol){
                                    //移动到的位置的棋子情况
                                    Piece moveToPiece = room.getPieceOnBoard(row, col);
                                    //移动到空位置时
                                    if (moveToPiece == null){
                                        selectMovePiece.setBoardPos(row,col); //选中棋子移动到新位置
                                        room.updateLimitRange(selectMovePiece); //更新落子限制
                                        room.doRuleAgent = null; //移除交互代理
                                        room.checkGameOver(); //检查游戏是否结束
                                    }
                                    //移动到的位置有棋子时
                                    else {
                                        //选中的棋子是万能棋子
                                        if (selectMovePiece.isUniversal){
                                            room.removePiece(moveToPiece); //移除原位置的棋子
                                            selectMovePiece.setBoardPos(row,col); //选中的棋子移动到新位置
                                            room.updateLimitRange(selectMovePiece); //更新落子限制
                                            room.doRuleAgent = null; //移除交互代理
                                            room.checkGameOver(); //检查游戏是否结束
                                        }
                                        //选中的棋子是活跃的飞行棋子，移动到的棋子是活跃的陆行棋子时
                                        else if (!selectMovePiece.isStone && selectMovePiece.isFlying && !moveToPiece.isStone && !moveToPiece.isFlying && !moveToPiece.isUniversal){
                                            room.removePiece(moveToPiece); //移除原位置的棋子
                                            selectMovePiece.setBoardPos(row,col); //选中的棋子移动到新位置
                                            room.updateLimitRange(selectMovePiece); //更新落子限制
                                            room.doRuleAgent = null; //移除交互代理
                                            room.checkGameOver(); //检查游戏是否结束
                                        }
                                    }
                                }
                            }
                        }

                        @Override
                        public void onRender() {
                            room.normalRender();
                            sourcePiece.renderInSkill(getSkillName());
                            if (selectMovePiece == null){
                                room.gameTip = "请选择1只史莱姆移动";
                            }
                            else {
                                room.signList.add(new TitleSign((selectMovePiece.boardCol + 0.5f) / room.curGrids[0].length, (selectMovePiece.boardRow + 0.35f) / room.curGrids.length, 0, "⟲", ColorCost.NEW_PUT_POINT_LIGHT, 0.5f));//提示已选择的棋子
                                room.gameTip = "请选择移动到的位置";
                            }
                        }
                    };
                    room.noticeAllRefreshGameInfo();
                }
            };
        }

    }

    /**
     * 临时的操作代理
     */
    private interface DoRuleAgent {
        void onClick(int row, int col);
        void onRender();
    }
}
